
#include <iostream>
#include "log.hpp"
#include "err.hpp"
#include "sock.hpp"
#include <sys/epoll.h>
#include <stdio.h>
#include <errno.h>
#include<functional>


namespace epoll_ns
{

    class EpollServer
    {
        using func_t = std::function<std::string(const std::string)>;
    public:
        EpollServer(func_t func, uint16_t port = 20000, int num = 64) : _port(port), _lisentsock(-1), _epollfd(-1), _num(num), _revs(nullptr), _func(func)
        {
        }

        void initServer()
        {
            // 1.创建socket
            _lisentsock = Sock::Socket();
            Sock::Bind(_lisentsock, _port);
            Sock::Listen(_lisentsock);

            // 2.创建epoll模型
            _epollfd = epoll_create(128);
            if (_epollfd < 0)
            {
                logMessage(FATAL, "epoll_create error: %s", strerror(errno));
                exit(EPOLL_CREATE_ERR);
            }
            // 3.添加_lisentsock 到epoll模型里面
            struct epoll_event event;
            event.events = EPOLLIN;
            event.data.fd = _lisentsock; // 这个data 的作用就是当事件就绪的时候 直接就知道那个 fd 就绪了
            int ret = epoll_ctl(_epollfd, EPOLL_CTL_ADD, _lisentsock, &event);
            if (ret == -1)
            {
                logMessage(FATAL, "epoll_ctl error, EPOLL_CTL_ADD _lisentsock error");
                exit(EPOLL_CTL_ERR);
            }

            // 4.申请就绪事件的空间
            _revs = new struct epoll_event[_num];
            logMessage(NORMAL, "init server success!!");
        }

        void start()
        {
            int timeout = 1000;
            for (;;)
            {
                int n = epoll_wait(_epollfd, _revs, _num, timeout);
                switch (n)
                {
                case 0:
                    /* 超时了 */
                    logMessage(NORMAL, "timeout ...!");
                    break;
                case -1:
                    /* error */
                    logMessage(WARNING, "epoll_wait error code: %d  strerror: %s", errno, strerror(errno));

                    break;
                default:
                    /* 有事件就绪 */
                    logMessage(NORMAL, "有事件就绪了!!");
                    handerevent(n);
                    break;
                }
            }
        }

        void handerevent(int max)
        {
            logMessage(DEBUG, "handerevent in");
            for (int i = 0; i < max; i++)
            {
                uint32_t events = _revs[i].events;
                int fd = _revs[i].data.fd;
                if ((fd == _lisentsock) && (events & EPOLLIN))
                {
                    /* _lisentsock 读事件到来了 */
                    std::string clientip;
                    uint16_t clientport;
                    int newsock = Sock::Accept(fd, &clientip, &clientport);
                    if (newsock < 0)
                    {
                        logMessage(ERROR, "accept error ");
                        continue; // 这里不能break , 可能不只有一个 event 就绪
                    }
                    // 添加到 epoll模型里面
                    struct epoll_event event;
                    event.events = EPOLLIN;
                    event.data.fd = newsock; // 这个data 的作用就是当事件就绪的时候 直接就知道那个 fd 就绪了
                    int ret = epoll_ctl(_epollfd, EPOLL_CTL_ADD, newsock, &event);
                    if (ret == -1)
                    {
                        logMessage(FATAL, "epoll_ctl error, EPOLL_CTL_ADD newsock error");
                        exit(EPOLL_CTL_ERR);
                    }
                }
                else if ((fd != _lisentsock) && (events & EPOLLIN))
                {
                    /*普通的读事件就绪了 */
                    char buf[1024];
                    int n = recv(fd, buf, sizeof(buf) - 1, 0);
                    if (n > 0)
                    {
                        buf[n] = 0;
                        logMessage(NORMAL, "client -> server : %s", buf);
                        std::string response = _func(buf);
                        send(fd, response.c_str(), response.size(), 0);
                    }
                    else if (n == 0)
                    {
                        // client 退出了
                        // 从 epoll 模型中 删掉 这个 fd;
                        // struct epoll_event event;
                        // event.events = EPOLLIN;
                        // event.data.fd = fd; // 这个data 的作用就是当事件就绪的时候 直接就知道那个 fd 就绪了
                        // int ret = epoll_ctl(_epollfd, EPOLL_CTL_DEL, fd, &event);
                        int ret = epoll_ctl(_epollfd, EPOLL_CTL_DEL, fd, nullptr); // event 可以不指定
                        if (ret == -1)
                        {
                            logMessage(FATAL, "epoll_ctl error, EPOLL_CTL_DEL fd error");
                        }

                        close(fd); // 一定要先移除, 再 close ;
                        logMessage(NORMAL, "client close fd!!");
                    }
                    else
                    {
                        // 错误
                        logMessage(ERROR, "recv error !!");
                        int ret = epoll_ctl(_epollfd, EPOLL_CTL_DEL, fd, nullptr); // event 可以不指定
                        if (ret == -1)
                        {
                            logMessage(FATAL, "epoll_ctl error, EPOLL_CTL_DEL fd error");
                        }
                    }
                }
            }
            logMessage(DEBUG, "handerevent out");
        }
        ~EpollServer()
        {
            if (_lisentsock != -1)
                close(_lisentsock);
            if (_epollfd != -1)
                close(_epollfd);
            if (_revs)
                delete[] _revs;
        }

    private:
        uint16_t _port;
        int _lisentsock;
        int _epollfd;
        struct epoll_event *_revs;
        int _num;
        func_t _func;
    };

} // namespace epoll_ns
